//
// Created by yangy on 2018/6/28.
//

#include "WIPlayer.h"

WIPlayer::WIPlayer(WIPlayState *playState, const char *url, JavaCallBack *listener) {
    this->url = url;
    this->listener = listener;
    this->playState = playState;

    pthread_mutex_init(&playMutex,NULL);
    pthread_mutex_init(&seek_mutex,NULL);
}

WIPlayer::~WIPlayer() {

    pthread_mutex_destroy(&playMutex);
    pthread_mutex_destroy(&seek_mutex);

}

void *decodeFFmpeg(void *data) {
    //强制类型转换
    WIPlayer *player = (WIPlayer *) data;
    player->audioDecodeThread();
    pthread_exit((void *) player->decodeThread);
}

void WIPlayer::prepare() {
    //创建子线程 并将本身传入
    pthread_create(&decodeThread, NULL, decodeFFmpeg, this);
}

int avfomat_callback (void *data){
    WIPlayer * player = (WIPlayer *) data;
    if (player->playState->exit){
        return AVERROR_EOF;
    }
    return 0;
}

void WIPlayer::audioDecodeThread() {

    pthread_mutex_lock(&playMutex);
    //注册所有组件并初始化网络
    av_register_all();
    avformat_network_init();

    av_format_ctx = avformat_alloc_context();

    av_format_ctx->interrupt_callback.callback =avfomat_callback;
    av_format_ctx->interrupt_callback.opaque = this;

    //打开文件或网络流
    if (avformat_open_input(&av_format_ctx, url, NULL, NULL) != 0) {
        LOGE("can not open url :%s", url);
        listener->onError(CHILD_THREAD,1001,"can not open url");
        exit = true;
        pthread_mutex_unlock(&playMutex);
        return;
    }

    //获取流信息
    if (avformat_find_stream_info(av_format_ctx, NULL) < 0) {
        LOGE("can not find streams from %s", url);
        listener->onError(CHILD_THREAD,1002,"can not find streams");
        pthread_mutex_unlock(&playMutex);
        exit = true;
        return;
    }

    //根据codecpar->codec_type获取音频流索引和音频流信息 此版本不能用streams[i]->codec来直接获取解码上下文
    for (int i = 0; i < av_format_ctx->nb_streams; ++i) {
        if (av_format_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
            if (audio == NULL) {
                audio = new WIAudio(playState, av_format_ctx->streams[i]->codecpar->sample_rate,
                                    listener);
                audio->audio_stream_index = i;
                audio->av_codec_par = av_format_ctx->streams[i]->codecpar;
                audio->duration = av_format_ctx->duration/AV_TIME_BASE;
                audio->time_base = av_format_ctx->streams[i]->time_base;
                this->duration = audio->duration;
                av_codec_init(audio->av_codec_par,&audio->av_codec_ctx);
            }
        } else if (av_format_ctx->streams[i]->codecpar->codec_id == AVMEDIA_TYPE_VIDEO){
            if (video == NULL){
                video = new WIVideo(listener,playState,av_format_ctx->streams[i]->codecpar);
                video->videoIndex = i;
                video->time_base = av_format_ctx->streams[i]->time_base;
                av_codec_init(video->avCodecParameters,&video->avCodecContext);
            }
        }
    }

    if (listener != NULL) {
        listener->onPrepared(CHILD_THREAD);
    }

    pthread_mutex_unlock(&playMutex);
}

void WIPlayer::start() {
    if (audio == NULL) {
        LOGE("audio is empty");
        return;
    }

    audio->play();

    int count = 0;
    //开始解码
    while (playState != NULL && !playState->exit) {

        if (playState->seek){
            continue;
        }

        if (audio->queueAudio->getQueueSize()>100){
            continue;
        }

        //新api提供了avpacket的申请方式 。此语句不能再while外面 因为申请的已经释放，必须重新申请
        AVPacket *avPacket = av_packet_alloc();

        pthread_mutex_lock(&seek_mutex);
        int ret = av_read_frame(av_format_ctx, avPacket);
        pthread_mutex_unlock(&seek_mutex);
        if ( ret == 0) {
            if (avPacket->stream_index == audio->audio_stream_index) {
                count++;
                audio->queueAudio->putAvPacket(avPacket);
                LOGE("queueAudio size is %d",audio->queueAudio->getQueueSize());
            } else if (avPacket->stream_index == video->videoIndex){
                count++;
                video->queue->putAvPacket(avPacket);
                LOGE("video queue size is %d",audio->queueAudio->getQueueSize());
            } else {
                //释放avpacket
                av_packet_free(&avPacket);
                av_free(avPacket);
            }
        } else {
            LOGE("解码结束共%d帧", count);
            //释放avpacket
            av_packet_free(&avPacket);
            av_free(avPacket);
            avPacket = NULL;
            break;
        }
    }
    LOGE("解码结束");
    exit = true;
}

void WIPlayer::release() {
     if (playState->exit)
         return;
    playState->exit = true;
    int sleepCount = 0;

    while (!exit){
        if (sleepCount>1000){
            exit = true;
        }
        sleepCount++;
        if(DEBUG){
            LOGI("exit ffmpeg %d",sleepCount);
        }
        av_usleep(1000*10);
    }

    if (audio!=NULL){
        LOGI("release audio");

        audio->releas();
        delete audio;
        audio = NULL;

        LOGI("release audio end");

    }

    if (av_format_ctx!=NULL){
        avformat_close_input(&av_format_ctx);
        avformat_free_context(av_format_ctx);
        av_format_ctx = NULL;
    }

    playState = NULL;
    listener = NULL;

}

void WIPlayer::seek(int64_t secds) {
    if (audio==NULL)
        return;
    if (audio->duration<=0)
        return;
    if (secds>=0&&secds<=audio->duration){
        pthread_mutex_lock(&seek_mutex);
        playState->seek = true;
        audio->queueAudio->clearPackets();
        audio->clock = 0;
        audio->new_time = 0;
        int64_t real = secds * AV_TIME_BASE;
        avformat_seek_file(av_format_ctx,-1,INT64_MIN,real,INT64_MAX,0);
        int ret = pthread_mutex_unlock(&seek_mutex);
        playState->seek = false;
    }
}

void WIPlayer::setVolume(int level) {
    audio->setVolume(level);
}

void WIPlayer::setMute(int mute) {
    audio->setMute(mute);
}

void WIPlayer::setpitch(double pitch) {
    if(audio!=NULL){
        audio->setpitch(pitch);
    }
}

void WIPlayer::settempo(double tempo) {
    if(audio!=NULL){
        audio->settempo(tempo);
    }
}

int WIPlayer::getSampleRate(){
    return audio->sample_rate;
}

void WIPlayer::startRecord(bool start) {
    audio->record = start;
}

void
WIPlayer::av_codec_init(AVCodecParameters *avCodecParameters, AVCodecContext **pAVCodecContext) {

    //获取解码器
    AVCodec *decoder = avcodec_find_decoder(avCodecParameters->codec_id);

    if (decoder == NULL) {
        LOGE("can not find decoder from %s", url);
        listener->onError(CHILD_THREAD,1003,"can not find decoder");
        exit = true;
        pthread_mutex_unlock(&playMutex);
        return;
    }

    //申请解码上下文
    *pAVCodecContext = avcodec_alloc_context3(decoder);

    if (!*pAVCodecContext) {
        LOGE("can not alloc accodecxtx");
        listener->onError(CHILD_THREAD,1004,"can not alloc accodecxtx");

        pthread_mutex_unlock(&playMutex);
        exit = true;
        return;
    }

    //将音频流信息填充到解码上下文
    if (avcodec_parameters_to_context(*pAVCodecContext, audio->av_codec_par) < 0) {
        LOGE("can not parameters to context");
        listener->onError(CHILD_THREAD,1005,"can not parameters to context");
        pthread_mutex_unlock(&playMutex);
        exit = true;
        return;
    }

    //打开解码器
    if (avcodec_open2(*pAVCodecContext, decoder, 0) != 0) {
        LOGE("can not open decoder from %s", url);
        listener->onError(CHILD_THREAD,1006,"can not open decoder");
        pthread_mutex_unlock(&playMutex);
        exit = true;
        return;
    }

}






